`timescale 1ns / 1ns
// Description: key debounce
// Author: JerryTech
// License: GPLv3

module key_debounce #(
    parameter SYS_FREQ = 100_000_000,
    parameter KEY_POLARITY  = 0,//0 is low active,1 is high active
    parameter DEBOUNCE_TIME = 40 //MS
)
(
    input   wire    sys_clk,
    input   wire    reset,

    input   wire    key_in,
    output  reg     key_debounce_out //high active
);

localparam DEBOUNCE_CYCLE = DEBOUNCE_TIME * SYS_FREQ / 1000;
localparam COUNTER_WIDTH = $clog2(DEBOUNCE_CYCLE);

reg [COUNTER_WIDTH: 0] key_debounce_counter;
reg key_lock;
wire key_pressed = KEY_POLARITY == 0 ? ~ key_in : key_in;

always@(posedge sys_clk) begin
    if(reset) begin
        key_debounce_counter    <= 'd0;
        key_debounce_out        <= 1'd0;
        key_lock                <= 1'b0;
    end
    else if(key_pressed) begin
        key_lock                <= key_debounce_counter == DEBOUNCE_CYCLE - 1 ? 1'b1                 : 1'b0;
        key_debounce_out        <= key_debounce_counter == DEBOUNCE_CYCLE - 1 ? ~ key_lock           : 1'b0;
        key_debounce_counter    <= key_debounce_counter == DEBOUNCE_CYCLE - 1 ? key_debounce_counter : key_debounce_counter + 1;
    end
    else begin
        key_debounce_counter    <= 'd0;
        key_debounce_out        <= 1'd0;
        key_lock                <= 1'b0;
    end
end

endmodule
